package com.share.common.utils.encryption;

import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.UUID;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.alibaba.fastjson.JSON;

/** 
* @author weigen.ye 
* @date 创建时间：2016年9月12日 下午7:17:36 
*
*/
public class EncryptUtils {
	
	private static final Logger LOG = LoggerFactory.getLogger(EncryptUtils.class);

	public static final Integer HTTP_SUCCESS_CODE = 1;
	public static final int RANDOM_STR_LEN = 32;
	public static final String signKey = "A*a#De]86~TXSAGb";
	public static final String key = "ABH:~UYJCV8*{t11";
	public static final String vi = "DN7LKNHKDGx*XDfK";
	
	public static String encrypt(String message) throws Exception {
		SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
		Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
		int blockSize = cipher.getBlockSize();
        byte[] dataBytes = message.getBytes("UTF-8");
        int plaintextLength = dataBytes.length;
        if (plaintextLength % blockSize != 0) {
            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
        }
        byte[] plaintext = new byte[plaintextLength];
        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
		IvParameterSpec iv = new IvParameterSpec(vi.getBytes("UTF-8"));
		cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
		return new String(Base64.encodeBase64(cipher.doFinal(plaintext)));
	}

	public static String decrypt(String message) {
		try {
			byte[] bytesrc = Base64.decodeBase64(message.getBytes("UTF-8"));
			SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
			IvParameterSpec iv = new IvParameterSpec(vi.getBytes("UTF-8"));
			cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
			byte[] retByte = cipher.doFinal(bytesrc);
			return new String(retByte).trim();
		} catch (Exception e) {
			LOG.error("decrypt error",e);
			new RuntimeException("des decrpty failed",e);
		}
		return null;
	}

	public static Map<String, String> signParamsForMD5(Map<String, String> requestMap) {
		if (requestMap != null) {
			Iterator<Entry<String, String>> it = requestMap.entrySet().iterator();
			StringBuffer sb = new StringBuffer();
			while (it.hasNext()) {
				sb.append(it.next().getValue());
			}
			requestMap.put("sign", DigestUtils.md5Hex(sb.append(signKey).toString()));
		}
		return requestMap;
	}
	
	private static String encrytParamsByJbhKey(Map<String,String> map) throws Exception {
		String encryptStr =  encrypt(JSON.toJSONString(map));
		map.clear();
		return encryptStr;
	}
	
	public static Map<String, String> signParamsWithMD5(Map<String, String> requestMap) {
		Map<String,String> params = new HashMap<String,String>();
		if (requestMap != null) {
			if(requestMap.containsKey("wid")){
				params.put("token", md5Sign(requestMap.get("wid")));
			}else{
				params.put("token", md5Sign(UUID.randomUUID().toString()));
			}
			params.put("businesscode", requestMap.get("businesscode"));
			requestMap.remove("businesscode");
			try {
				params.put("data", encrytParamsByJbhKey(requestMap));
			} catch (Exception e) {
				LOG.error("Encrypt params data error.",e);
			}
			params.put("channel", "mshop");
			params.put("random", generateRandomString());
			String sortedParamValue = sortParamsValueByKeyAsc(params);
			params.put("sign", md5Sign(sortedParamValue+signKey));
		}
		return params;
	}
	
	private static String sortParamsValueByKeyAsc(Map<String,String> map){
		if (map != null) {
			List<String> arrayList = new ArrayList<String>(map.keySet());
			Collections.sort(arrayList, new Comparator<String>() {
				public int compare(String key1, String key2) {
					return (key1.compareTo(key2));
				}
			});
			
			StringBuilder sb = new StringBuilder();
			for (Iterator<String> iter = arrayList.iterator(); iter.hasNext();) {
				   String key = iter.next();
				   sb.append(map.get(key));
			}
			return sb.toString();
		}
		return null;
	}
	
	public static String generateRandomString(){  
        String baseStr="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";  
        Random random = new Random();  
        StringBuilder sb = new StringBuilder();
        for(int i = 0 ; i < RANDOM_STR_LEN; ++i){  
            int offset = random.nextInt(baseStr.length());
            sb.append(baseStr.charAt(offset));  
        }  
        return sb.toString();  
    } 
	
	private static String md5Sign(String input) {
		return DigestUtils.md5Hex(input);
	}
	
	/*
	public static Map<String, String> getReqeustMapForDES(Map<String, String> requestMap) throws Exception {
		Map<String, String> paramMap = new HashMap<>();
		if (requestMap != null) {
			Iterator<Entry<String, String>> it = requestMap.entrySet().iterator();
			while (it.hasNext()) {
				Entry<String, String> entry = it.next();
				paramMap.put(entry.getKey(), encrypt(entry.getValue()));
			}
			String time = String.valueOf(System.currentTimeMillis());
			paramMap.put("time", time);
			paramMap.put("newsession", DigestUtils.md5Hex(Base64.encodeBase64(new String(DigestUtils.md5Hex(sessonCode) + time).getBytes())));
		}
		return paramMap;
	}*/

	public static String login() {
		Map<String, String> param = new HashMap<>();
		param.put("username", "wsj");
		param.put("apiKey", "wazyl1314");
		return "";
		// 获取sessionId
//		return soapCall(param, JbhSoapMethodAndResponse.Login);
	}

	

//	public static String soapCall(Map<String, String> paramMap, JbhSoapMethodAndResponse mr) {
//
//		return soapCall(paramMap, mr.getTargetMethod(), mr.getResponseElement());
//	}

	public static String soapCall(Map<String, String> paramMap, String targetMethod, String responseNodeName) {

		SOAPConnection conn = null;

		try {

			// 创建连接
			SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
			conn = soapConnFactory.createConnection();

			// 创建消息对象
			MessageFactory messageFactory = MessageFactory.newInstance();
			SOAPMessage message = messageFactory.createMessage();

			// 创建soap消息主体==========================================
			SOAPPart soapPart = message.getSOAPPart();// 创建soap部分
			SOAPEnvelope envelope = soapPart.getEnvelope();
			SOAPBody body = envelope.getBody();
			// =====================================
			SOAPElement bodyElement = body.addChildElement(envelope.createName(targetMethod, "SOAP-ENV", "http://schemas.xmlsoap.org/soap/encoding/"));

			if (paramMap != null) {
				Iterator<Entry<String, String>> it = paramMap.entrySet().iterator();
				while (it.hasNext()) {
					Entry<String, String> entry = it.next();
					bodyElement.addChildElement(entry.getKey()).addTextNode(entry.getValue());
				}
			}

			message.saveChanges();
			// 打印客户端发出的soap报文，做验证测试
			System.out.println(" REQUEST: ");
			message.writeTo(System.out);
			System.out.println(" ");

			// * 实际的消息是使用 call()方法发送的，该方法接收消息本身和目的地作为参数，并返回第二个 SOAPMessage 作为响应。
			// * call方法的message对象为发送的soap报文，url为mule配置的inbound端口地址。

			URL url = new URL("http://www.jbw666.com:8080/api/v2_soap");
			System.out.println(url);
			// 响应消息
			// ===========================================================================
			SOAPMessage reply = conn.call(message, url);
			SOAPBody soapBody = reply.getSOAPBody();
			Node node = soapBody.getElementsByTagName(responseNodeName).item(0);
//			System.out.print("returnValue:" + node.getTextContent());
//			String resultVal = node.getTextContent();
			
			System.out.println("RESPONSE:");
			// ==================创建soap消息转换对象
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			Source sourceContent = reply.getSOAPPart().getContent();
			StreamResult result = new StreamResult(System.out);
			transformer.transform(sourceContent, result);
			if (!targetMethod.equals("login")) {
				Document doc = reply.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
				if (doc.getElementsByTagName("faultcode") != null) {
					if (doc.getElementsByTagName("faultcode").item(0) != null) {
//						String faultcode = doc.getElementsByTagName("faultcode").item(0).getTextContent();
//						if (faultcode.equals("5")) {
//							System.err.println("Session expired!!!!");
//							throw new SessionTimeoutException("", "");
//						}
					}
				}
			}
//			return resultVal;
//		} catch (SessionTimeoutException se) {
//			throw se;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SOAPException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	
	
	public static void main(String[] args) {
		try {
			System.out.println(encrypt("12319090"));
			System.out.println(decrypt(encrypt("12319090")));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
